﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Paxman.Misc;

namespace Paxman.Objects
{
    class Enemy:Sprite
    {
        int id;

        Animation walkingUpAnim;
        Animation walkingDownAnim;
        Animation walkingLeftAnim;
        Animation walkingRightAnim;

        Direction currentDirection;
        Direction CurrentDirection
        {
            get { return currentDirection; }
            set
            {
                currentDirection = value;
                switch (currentDirection)
                {
                    case Direction.Up:
                        currentAnimation = walkingUpAnim;
                        break;
                    case Direction.Down:
                        currentAnimation = walkingDownAnim;
                        break;
                    case Direction.Left:
                        currentAnimation = walkingLeftAnim;
                        break;
                    case Direction.Right:
                        currentAnimation = walkingRightAnim;
                        break;
                }
            }
        }

        static Map map;

        static Texture2D texture;

        /// <summary>
        /// Posição do jogador para montar os algoritmos
        /// de movimentação
        /// </summary>
        Vector2 playerPosition;

        /// <summary>Posição do ultimo tile do enemy</summary>
        Point lastTilePosition;

        public Enemy(int id)
        {
            this.id = id;
            vel = 3;
            base.texture = Enemy.texture;
            playerPosition = Vector2.Zero;

            SetOffset(Util.borderLeftGameArea, Util.borderTopGameArea);

            // posicao onde começa a textura de cada inimigo
            int texPosition = (id - 1) * 128;

            walkingRightAnim = new Animation("WalkingRight", 30, 32, 0 + texPosition, 2, 10);
            walkingLeftAnim = new Animation("WalkingLeft", 30, 32, 32 + texPosition, 2, 10);
            walkingUpAnim = new Animation("WalkingUp", 30, 32, 64 + texPosition, 2, 10);
            walkingDownAnim = new Animation("WalkingDown", 30, 32, 96 + texPosition, 2, 10);
        }

        public static void LoadContent(ContentManager content, Map map)
        {
            Enemy.texture = content.Load<Texture2D>("enemies");
            Enemy.map = map;
        }

        public void SetInitialPosition()
        {
            CurrentDirection = Direction.Right;

            switch (id)
            {
                // vermelho
                case 1: Center = new Vector2(252, 207);
                    break;
                // azul
                case 2: Center = new Vector2(216, 261);
                    break;
                // rosa
                case 3: Center = new Vector2(252, 261);
                    break;
                // laranja
                case 4: Center = new Vector2(288, 261);
                    break;
            }

            lastTilePosition = map.TransformInGridPosition(Center);
        }

        public void Update(GameTime gameTime, Vector2 playerPosition)
        {
            this.playerPosition = playerPosition;

            switch (CurrentDirection)
            {
                case Direction.Up:
                    position.Y -= vel;
                    break;
                case Direction.Down:
                    position.Y += vel;
                    break;
                case Direction.Left:
                    position.X -= vel;
                    break;
                case Direction.Right:
                    position.X += vel;
                    break;
            }

            CheckMapCollision();

            // grava o ultimo tile passado
            Point newTilePosition = map.TransformInGridPosition(Center);
            if (lastTilePosition != newTilePosition)
                lastTilePosition = newTilePosition;
        }

        private void GetNewRandomDirection()
        {
            //timeNewDirection += gameTime.ElapsedGameTime.Milliseconds;
            //if (timeNewDirection > 500)
            //{
                Point enemytilePosTemp = map.TransformInGridPosition(Center);
                bool getNewDirection = false;

                while (!getNewDirection)
                {
                    CurrentDirection = (Direction)Util.NextRandom(4);
                    Point enemytilePos = enemytilePosTemp;
                    switch (CurrentDirection)
                    {
                        case Direction.Up:
                            enemytilePos.Y--;
                            if (map.GetTileType(enemytilePos) != TileType.Wall)
                            {
                                //currentAnimation = walkingUpAnim;
                                getNewDirection = true;
                            }
                            break;
                        case Direction.Down:
                            enemytilePos.Y++;
                            if (map.GetTileType(enemytilePos) != TileType.Wall)
                            {
                                //currentAnimation = walkingDownAnim;
                                getNewDirection = true;
                            }
                            break;
                        case Direction.Left:
                            enemytilePos.X--;
                            if (map.GetTileType(enemytilePos) != TileType.Wall)
                            {
                                //currentAnimation = walkingLeftAnim;
                                getNewDirection = true;
                            }
                            break;
                        case Direction.Right:
                            enemytilePos.X++;
                            if (map.GetTileType(enemytilePos) != TileType.Wall)
                            {
                                //currentAnimation = walkingRightAnim;
                                getNewDirection = true;
                            }
                            break;
                    }
                }

                //timeNewDirection = 0;
            //}
        }

        /// <summary>
        /// Escolhe uma nova direção a cada "esquina"
        /// Atualmente é baseado diretamente na posição do jogador
        /// </summary>
        private void ChooseNewDirection()
        {
            // direcao horizontal e vertical
            Direction horDirection;
            Direction vertDirection;

            bool canMoveHor;
            bool canMoveVert;

            // determina horizontalmente e verticalmente
            // onde está o ponto de destino
            if (playerPosition.X > Center.X)
                horDirection = Direction.Right;
            else
                horDirection = Direction.Left;

            if (playerPosition.Y > Center.Y)
                vertDirection = Direction.Down;
            else
                vertDirection = Direction.Up;

            Point enemyTilePosTemp = map.TransformInGridPosition(Center);
            Vector2 centerCurrentTile = map.GetCenterTileInPosition(Center);

            while (true)
            {
                canMoveHor = false;
                canMoveVert = false;

                // determina se as direções horizontais
                // e verticais estão livres para se movimentar

                Point enemytilePos = enemyTilePosTemp;
                switch (horDirection)
                {
                    case Direction.Left:
                        enemytilePos.X--;
                        if (map.GetTileType(enemytilePos) != TileType.Wall)
                            canMoveHor = true;
                        break;
                    case Direction.Right:
                        enemytilePos.X++;
                        if (map.GetTileType(enemytilePos) != TileType.Wall)
                            canMoveHor = true;
                        break;
                }

                enemytilePos = enemyTilePosTemp;
                switch (vertDirection)
                {
                    case Direction.Up:
                        enemytilePos.Y--;
                        if (map.GetTileType(enemytilePos) != TileType.Wall)
                            canMoveVert = true;
                        break;
                    case Direction.Down:
                        enemytilePos.Y++;
                        if (map.GetTileType(enemytilePos) != TileType.Wall)
                            canMoveVert = true;
                        break;
                }

                if (canMoveHor && !canMoveVert)
                {
                    CurrentDirection = horDirection;
                    return;
                }
                else if (!canMoveHor && canMoveVert)
                {
                    CurrentDirection = vertDirection;
                    return;
                }
                // se as duas direções estiverem disponiveis
                // pega a distancia horizontal e vertical em relação
                // ao ponto destino, e escolha a mais longa
                else if (canMoveHor && canMoveVert)
                {
                    float distanceHor;
                    float distanceVert;

                    if (playerPosition.X > Center.X)
                        distanceHor = playerPosition.X - Center.X;
                    else
                        distanceHor = Center.X - playerPosition.X;

                    if (playerPosition.Y > Center.Y)
                        distanceVert = playerPosition.Y - Center.Y;
                    else
                        distanceVert = Center.Y - playerPosition.Y;

                    if (distanceHor > distanceVert)
                        CurrentDirection = horDirection;
                    else
                        CurrentDirection = vertDirection;

                    return;
                }
                // se nenhuma das direções estiverem disponiveis
                // inverte as direções e volta ao inicio do loop
                else
                {
                    if (horDirection == Direction.Left)
                        horDirection = Direction.Right;
                    else
                        horDirection = Direction.Left;

                    if (vertDirection == Direction.Up)
                        vertDirection = Direction.Down;
                    else
                        vertDirection = Direction.Up;
                }
            }
        }

        private void CheckMapCollision()
        {
            Point enemytilePos = map.TransformInGridPosition(Center);
            Vector2 centerCurrentTile = map.GetCenterTileInPosition(Center);

            switch (CurrentDirection)
            {
                case Direction.Up:
                    enemytilePos.Y--;
                    if (map.GetTileType(enemytilePos) == TileType.Wall && (Center.Y < centerCurrentTile.Y))
                        Center = centerCurrentTile;
                    break;
                case Direction.Down:
                    enemytilePos.Y++;
                    if (map.GetTileType(enemytilePos) == TileType.Wall && (Center.Y > centerCurrentTile.Y))
                        Center = centerCurrentTile;
                    break;
                case Direction.Left:
                    enemytilePos.X--;
                    if (map.GetTileType(enemytilePos) == TileType.Wall && (Center.X < centerCurrentTile.X))
                        Center = centerCurrentTile;
                    break;
                case Direction.Right:
                    enemytilePos.X++;
                    if (map.GetTileType(enemytilePos) == TileType.Wall && (Center.X > centerCurrentTile.X))
                        Center = centerCurrentTile;
                    break;
            }

            Point tilePosition = map.TransformInGridPosition(Center);
            if (tilePosition != lastTilePosition && VerifyOnCorner())
                ChooseNewDirection();
        }

        /// <summary>Verifica se está numa esquina</summary>
        private bool VerifyOnCorner()
        {
            Point tilePos = map.TransformInGridPosition(Center);

            bool horizontal = false;
            switch (CurrentDirection)
            {
                case Direction.Up:
                    horizontal = false;
                    break;
                case Direction.Down:
                    horizontal = false;
                    break;
                case Direction.Left:
                    horizontal = true;
                    break;
                case Direction.Right:
                    horizontal = true;
                    break;
            }

            if (horizontal && map.GetTileType(new Point(tilePos.X, tilePos.Y - 1)) != TileType.Wall)
            //if (map.GetTileType(new Point(tilePos.X, tilePos.Y - 1)) != TileType.Wall)
                return true;

            if (horizontal && map.GetTileType(new Point(tilePos.X, tilePos.Y + 1)) != TileType.Wall)
            //if (map.GetTileType(new Point(tilePos.X, tilePos.Y + 1)) != TileType.Wall)
                return true;

            if (!horizontal && map.GetTileType(new Point(tilePos.X - 1, tilePos.Y)) != TileType.Wall)
            //if (map.GetTileType(new Point(tilePos.X - 1, tilePos.Y)) != TileType.Wall)
                return true;

            if (!horizontal && map.GetTileType(new Point(tilePos.X + 1, tilePos.Y)) != TileType.Wall)
            //if (map.GetTileType(new Point(tilePos.X + 1, tilePos.Y)) != TileType.Wall)
                return true;
            else
                return false;
        }
    }
}
